<?php

namespace App\Model;

use App\Exceptions\BizException;
use Intervention\Image\ImageManager;

class Upload
{
    // 上传类型，file或image，不设置则不校验
    public $fileType;

    // 图片最大宽度
    public $width;

    // 文件允许大小
    public $maxSize;

    // 文件类型
    public $fileExt;

    // 文件允许类型
    public $allowTypeFiles = [
        'file' => [
            'png', 'jpg', 'jpeg', 'gif', 'bmp',
            'flv', 'swf', 'mkv', 'avi', 'rm', 'rmvb', 'mpeg', 'mpg',
            'ogg', 'ogv', 'mov', 'wmv', 'mp4', 'webm', 'mp3', 'wav', 'mid',
            'rar', 'zip', 'tar', 'gz', '7z', 'bz2', 'cab', 'iso',
            'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf', 'txt', 'md', 'xml'
        ],
        'image' => ['png', 'jpg', 'jpeg', 'gif', 'bmp'],
    ];

    public function __construct($fileType = 'image', $width = 500, $maxSize = 10000000)
    {
        $this->fileType = $fileType;
        $this->width = $width;
        $this->maxSize = $maxSize;
    }

    /**
     * 执行上传
     *
     * @param string $domain 图片前缀域名
     * @return string 图片地址
     */
    public function handle($domain)
    {
        // 获取上传文件
        $fileArr = array_values($_FILES);
        $file = $fileArr[0];

        // 获取文件后缀
        $this->fileExt = $this->getFileExt($file['name']);

        $this->check($file);
        return $domain . $this->save($file['tmp_name']);
    }

    /**
     * 文件校验
     *
     * @param $file
     * @throws BizException
     */
    public function check($file)
    {
        // 校验错误码
        if (isset($file['error']) && $file['error'] > 0) {
            $error = $this->getErrorNoMsg($file['error']);
            throw new BizException($error);
        }

        // 校验文件大小
        if ($file['size'] > $this->maxSize)
            throw new BizException('文件大小超过限制');

        // 校验文件类型
        $allowFiles = $this->allowTypeFiles[$this->fileType];
        if ($this->fileType && !in_array($this->fileExt, $allowFiles))
            throw new BizException('文件类型不允许');
    }

    /**
     * 文件保存
     *
     * @param $file
     * @return string
     */
    public function save($file)
    {
        $manager = new ImageManager();
        $image = $manager->make($file);

        $uniqueName = $this->produceFileName(); // 唯一文件名

        // 若是图片缩放处理
        if ($this->fileType == 'image' && $this->width && $image->width() > $this->width)
            $image->widen($this->width);

        // 保存图片
        $localPath = base_path('public/upload/') . date('ymd');
        !is_dir($localPath) && mkdir($localPath, 0777);
        $image->save($localPath . '/' . $uniqueName);

        return '/upload/' . date('ymd') . '/' . $uniqueName;
    }

    /**
     * 产生一个唯一的文件名
     *
     * @return string
     */
    public function produceFileName()
    {
        return date('ymdHis') . mt_rand(1000, 9999) . '.' . $this->fileExt;
    }

    /**
     * 由错误号获取错误信息
     *
     * @param string $errorNo 错误号
     * @return string
     */
    public function getErrorNoMsg($errorNo)
    {
        switch ($errorNo) {
            case 1:
                $error = '上传的文件超过php.ini允许的大小！';
                break;
            case 2:
                $error = '上传文件的大小超过表单允许的大小！';
                break;
            case 3:
                $error = '文件只有部分被上传！';
                break;
            case 4:
                $error = '没有文件被上传！';
                break;
            case 6:
                $error = '找不到临时文件夹！';
                break;
            case 7:
                $error = '文件写入失败！';
                break;
            default:
                $error = '未知上传错误！';
        }

        return $error;
    }

    /**
     * 获取文件后缀
     *
     * @param $fileName
     * @return string
     */
    public function getFileExt($fileName)
    {
        $fileExt = substr($fileName, strrpos($fileName, '.') + 1);
        return strtolower(trim($fileExt));
    }
}